#include <QPainter>
#include <QGraphicsSceneMouseEvent>
#include <QMenu>
#include <QMessageBox>
#include <QGraphicsScene>
#include <QAction>
#include <QDialog>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QLabel>
#include <QSpinBox>
#include <QDialogButtonBox>
#include "plcelement.h"
#include "plcgraphicsscene.h"

PlcElement::PlcElement(QGraphicsItem *parent)
    : QGraphicsObject(parent), m_type(PlcInstructionType::NormallyOpen)
{
    setFlag(QGraphicsItem::ItemIsMovable, true);
    setFlag(QGraphicsItem::ItemIsSelectable, true);
}

PlcElement::~PlcElement()
{
    // 若外部直接 delete 元件，确保连线不会遗留或悬空
    removeConnections();
}

void PlcElement::setOn(bool on)
{
    if (m_on == on) return;
    m_on = on;
    // 添加调试输出 - 打印元件状态变化
    qDebug() << "元件状态变化 - 类型:" << static_cast<int>(m_type)
             << "前缀:" << m_propPrefix << "值:" << m_propValue
             << "ON状态:" << on;
    update();
}

bool PlcElement::isOn() const
{
    return m_on;
}

void PlcElement::setInstructionType(PlcInstructionType type)
{
    m_type = type;
    // 在设置类型后，如果是比较元件，确保前缀和默认值正确
    if (isComparator())
    {
        m_propPrefix = QString("D");
        m_propValue = 0;  // D0
        m_propValue2 = 1; // D1
    }
    update();
}

PlcInstructionType PlcElement::instructionType() const
{
    return m_type;
}

QRectF PlcElement::boundingRect() const
{
    return QRectF(0,0,m_width,m_height);
}

void PlcElement::setSize(double width, double height)
{
    m_width = width;
    m_height = height;
    update();
}

void PlcElement::verticalLine(QPainter *painter, int leftMargin, int rightMargin)
{
    painter->drawLine(leftMargin, 5, leftMargin, m_height - 5);
    painter->drawLine(rightMargin, 5, rightMargin, m_height - 5);
}

void PlcElement::enlarge(QPainter *painter, int leftMargin, int rightMargin, const QString& symbol)
{
    QFont myFont = painter->font();
    myFont.setPointSize(16);
    painter->setFont(myFont);
    painter->drawText(QRect(leftMargin, 5, rightMargin - leftMargin, m_height - 10), Qt::AlignCenter, symbol);
}

void PlcElement::addConnection(ConnectionItem *connection)
{
    if (!connection) return;
    if (!m_connections.contains(connection)) {
        m_connections.append(connection);
    }
}

void PlcElement::removeConnection(ConnectionItem *connection)
{
    m_connections.removeAll(connection); // 只移出列表，不 delete
}

void PlcElement::removeConnections()
{
    // 拷贝一份，避免遍历中修改原列表
    const auto conns = m_connections;
    m_connections.clear();

    for (ConnectionItem* c : conns) {
        if (!c) continue;

        // 通知另一端的元件把这条线从它的列表中移除（若另一端是锚点则没有元件）
        if (!c->startIsAnchor() && c->startItem() == this)
        {
            if (!c->endIsAnchor() && c->endItem())
            {
                c->endItem()->removeConnection(c);
            }
        }
        else if (!c->endIsAnchor() && c->endItem() == this)
        {
            if (!c->startIsAnchor() && c->startItem())
            {
                c->startItem()->removeConnection(c);
            }
        }

        // 从场景中移除并销毁这条连线
        if (scene())
        {
            scene()->removeItem(c);
        }
        delete c;
    }
}

QList<ConnectionItem *> PlcElement::connections() const
{
    return m_connections;
}

QPointF PlcElement::startConnectionPoint() const
{
    int midY = m_height / 2;
    // 使用元件右侧边界作为起点
    return mapToScene(QPointF(m_width, midY));
}

QPointF PlcElement::endConnectionPoint() const
{
    int midY = m_height / 2;
    // 使用元件左侧边界作为终点
    return mapToScene(QPointF(0, midY));
}

QVariant PlcElement::itemChange(GraphicsItemChange change, const QVariant &value)
{
    if (change == ItemPositionHasChanged)
    {
        // 位置实际变化后才更新
        foreach (ConnectionItem *conn, m_connections)
        {
            conn->updatePosition();
        }
    }
    return QGraphicsObject::itemChange(change, value);
}

int PlcElement::type() const
{
    return Type;
}

static inline bool supportsOnOff(PlcInstructionType t)
{
    return t == PlcInstructionType::NormallyOpen
           || t == PlcInstructionType::NormallyClosed
           || t == PlcInstructionType::Coil;
}

void PlcElement::simpleDialog(PlcInstructionType t)
{
    QString labelText;
    QString prefix;
    int minVal = 0;
    int maxVal = 4000;

    if (t == PlcInstructionType::NormallyOpen || t == PlcInstructionType::NormallyClosed || t == PlcInstructionType::Coil)
    {
        labelText = QString("线圈：M");
        prefix = QString("M");
    }
    else
    {
        prefix = QString("D");
        // 显示两行寄存器
        QDialog dlg;
        dlg.setWindowTitle(QString("设置寄存器"));

        auto *spin1 = new QSpinBox(&dlg);
        spin1->setRange(0, 4000);
        spin1->setValue(m_propValue2 >= 0 && m_propValue2 <= 4000 ? m_propValue : 0);

        auto *spin2 = new QSpinBox(&dlg);
        spin2->setRange(0, 4000);
        spin2->setValue(m_propValue2 >= 0 && m_propValue2 <= 4000 ? m_propValue2 : 0);

        auto *lbl1 = new QLabel(QString("左寄存器: D"), &dlg);
        auto *lbl2 = new QLabel(QString("右寄存器: D"), &dlg);

        auto *row1 = new QHBoxLayout();
        row1->addWidget(lbl1);
        row1->addWidget(spin1);

        auto *row2 = new QHBoxLayout();
        row2->addWidget(lbl2);
        row2->addWidget(spin2);

        auto *btns = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dlg);
        QObject::connect(btns, &QDialogButtonBox::accepted, &dlg, &QDialog::accept);
        QObject::connect(btns, &QDialogButtonBox::rejected, &dlg, &QDialog::reject);

        auto *mainLay = new QVBoxLayout(&dlg);
        mainLay->addLayout(row1);
        mainLay->addLayout(row2);
        mainLay->addWidget(btns);

        if (dlg.exec() == QDialog::Accepted)
        {
            m_propPrefix = prefix;
            m_propValue  = spin1->value();
            m_propValue2 = spin2->value();
            qDebug() << "设置寄存器: D" << m_propValue << "和 D" << m_propValue2;
            update();
        }
        return; // 直接返回，避免继续执行下面的单寄存器逻辑
    }

    // 单寄存器通用逻辑（常开/常闭/线圈）
    QDialog dlg;
    dlg.setWindowTitle(QStringLiteral("属性"));
    auto *lbl = new QLabel(labelText, &dlg);
    auto *spin = new QSpinBox(&dlg);
    spin->setRange(minVal, maxVal);

    if (m_propPrefix == prefix)
    {
        spin->setValue(std::clamp(m_propValue, minVal, maxVal));
    }
    else
    {
        spin->setValue(minVal);
    }

    auto *btns = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dlg);
    QObject::connect(btns, &QDialogButtonBox::accepted, &dlg, &QDialog::accept);
    QObject::connect(btns, &QDialogButtonBox::rejected, &dlg, &QDialog::reject);

    auto *row = new QHBoxLayout();
    row->addWidget(lbl);
    row->addWidget(spin, 1);

    auto *mainLay = new QVBoxLayout(&dlg);
    mainLay->addLayout(row);
    mainLay->addWidget(btns);

    if (dlg.exec() == QDialog::Accepted)
    {
        int oldV = m_propValue;
        m_propPrefix = prefix;
        m_propValue  = spin->value();
        qDebug() << "设置线圈: M" << m_propValue;
        // 仅当前缀为 M 且数值变更时，通知外部更新监控集合
        if (m_propPrefix.compare(QStringLiteral("M"), Qt::CaseInsensitive) == 0 && oldV != m_propValue) {
            emit coilAddressChanged(oldV, m_propValue);
        }
        update();
    }
}

const QString &PlcElement::propPrefix() const
{
    return m_propPrefix;
}

int PlcElement::propValue() const
{
    return m_propValue;
}

int PlcElement::propValue2() const
{
    return m_propValue2;
}

void PlcElement::setPropPrefix(const QString &p)
{
    m_propPrefix = p;
    update();
}

void PlcElement::setPropValue(int v)
{
    if (v != m_propValue) {
        // 若当前是 M 前缀，同步通知地址变更
        if (m_propPrefix.compare(QStringLiteral("M"), Qt::CaseInsensitive) == 0) {
            emit coilAddressChanged(m_propValue, v);
        }
        m_propValue = v;
        update();
    }
}

void PlcElement::setPropValue2(int v)
{
    m_propValue2 = v;
    update();
}

bool PlcElement::isComparator() const
{
    switch (m_type)
    {
        case PlcInstructionType::Greater:
        case PlcInstructionType::GreaterEqual:
        case PlcInstructionType::Less:
        case PlcInstructionType::LessEqual:
        case PlcInstructionType::Equal:
        case PlcInstructionType::NotEqual:
        {
            return true;
        }
        default:
        {
            return false;
        }
    }
}

void PlcElement::updateCompareStateFromD(const QHash<int, quint16>& dregs)
{
    if (!isComparator())
    {
        return; // 非比较元件不处理
    }

    // 仅当前缀为 D 时进行比较（避免误用其他前缀）
    if (m_propPrefix.compare(QString("D"), Qt::CaseInsensitive) != 0)
    {
        setOn(false);
        return;
    }

    // 取 D1 / D2 的寄存器地址（来自属性对话框）
    const int d1Addr = m_propValue;   // D1
    const int d2Addr = m_propValue2;  // D2

    // 没有找到地址则按 OFF 处理
    if (!dregs.contains(d1Addr) || !dregs.contains(d2Addr))
    {
        setOn(false);
        return;
    }

    // 采用（quint16）存储
    const quint16 v1 = dregs.value(d1Addr);
    const quint16 v2 = dregs.value(d2Addr);

    // 更新“实际值”并决定是否需要重绘
    // bool valuesChanged = (m_leftRegisterValue  != v1) || (m_rightRegisterValue != v2);
    // m_leftRegisterValue  = v1;
    // m_rightRegisterValue = v2;

    qDebug() << "比较 D" << d1Addr << "和 D" << d2Addr << ":"
             << v1 << "==" << v2 << (v1 == v2 ? "TRUE" : "FALSE");

    bool on = false;
    switch (m_type)
    {
        case PlcInstructionType::Greater:
        {
            on = (v1 >  v2);
            break;
        }
        case PlcInstructionType::GreaterEqual:
        {
            on = (v1 >= v2);
            break;
        }
        case PlcInstructionType::Less:
        {
            on = (v1 <  v2);
            break;
        }
        case PlcInstructionType::LessEqual:
        {
            on = (v1 <= v2);
            break;
        }
        case PlcInstructionType::Equal:
        {
            on = (v1 == v2);
            break;
        }
        case PlcInstructionType::NotEqual:
        {
            on = (v1 != v2);
            break;
        }
        default:
        {
            on = false;
            break;
        }
    }

    // 使用已有接口，触发重绘（浅绿色背景）
    // bool prevOn = isOn();
    setOn(on);
    // if (!valuesChanged && (prevOn == on))
    // {
        // 只有数值变更但 on/off 未变更时，手动刷新以更新下方文字
        // update();
    // }
}

void PlcElement::setLeftRegisterValue(quint16 value)
{
    if (m_leftRegisterValue != value)
    {
        m_leftRegisterValue = value;
        update(); // 触发重绘
    }
}

void PlcElement::setRightRegisterValue(quint16 value)
{
    if (m_rightRegisterValue != value)
    {
        m_rightRegisterValue = value;
        update(); // 触发重绘
    }
}

void PlcElement::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
    QMenu menu;
    QAction *propAct = menu.addAction(QStringLiteral("属性"));

    if (supportsOnOff(m_type))
    {
        QAction *copyAct = menu.addAction(QStringLiteral("复制"));
        QAction *delAct  = menu.addAction(QStringLiteral("删除"));
        menu.addSeparator();
        QAction *actOn  = menu.addAction(QStringLiteral("置ON"));
        QAction *actOff = menu.addAction(QStringLiteral("置OFF"));

        QAction *chosen = menu.exec(event->screenPos());
        if (!chosen) return;

        if (chosen == propAct)
        {
            simpleDialog(m_type);
        }
        else if (chosen == copyAct)
        {
            if (auto *sc = qobject_cast<PlcGraphicsScene*>(scene()))
            {
                sc->copyFrom(this); // 交给场景保存“剪贴板”
            }
        }
        else if (chosen == delAct)
        {
            // 删除本元件及连接
            removeConnections();
            if (scene())
            {
                scene()->removeItem(this);
            }
            delete this;
        }
        else if (chosen == actOn)
        {
            setOn(true);
            // 触发写线圈信号
            emit writeCoilRequested(m_propValue, true);
        }
        else if (chosen == actOff)
        {
            setOn(false);
            // 触发写线圈信号
            emit writeCoilRequested(m_propValue, false);
        }
        return;
    }
    else
    {
        QAction *setValueAct = nullptr;  // 设置寄存器值动作
        propAct->setText(QString("设置寄存器"));
        setValueAct = menu.addAction(QString("设置寄存器值"));
        QAction *copyAct = menu.addAction(QStringLiteral("复制"));
        QAction *delAct  = menu.addAction(QStringLiteral("删除"));
        QAction *chosen  = menu.exec(event->screenPos());

        if (chosen == propAct)
        {
            simpleDialog(m_type);
        }
        else if (chosen == setValueAct)
        {
            // 弹出设置寄存器值对话框
            QDialog dlg;
            dlg.setWindowTitle(QStringLiteral("设置寄存器值"));
            QVBoxLayout vlay(&dlg);

            // 第一行：左寄存器
            QHBoxLayout hlay1;
            QLabel lblLeft("左寄存器值: ");
            QSpinBox sbLeft;
            sbLeft.setRange(0, 65535);
            sbLeft.setValue(m_leftRegisterValue);
            hlay1.addWidget(&lblLeft);
            hlay1.addWidget(&sbLeft);
            vlay.addLayout(&hlay1);

            // 第二行：右寄存器
            QHBoxLayout hlay2;
            QLabel lblRight("右寄存器值: ");
            QSpinBox sbRight;
            sbRight.setRange(0, 65535);
            sbRight.setValue(m_rightRegisterValue);
            hlay2.addWidget(&lblRight);
            hlay2.addWidget(&sbRight);
            vlay.addLayout(&hlay2);

            QDialogButtonBox bb(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
            vlay.addWidget(&bb);
            connect(&bb, &QDialogButtonBox::accepted, &dlg, &QDialog::accept);
            connect(&bb, &QDialogButtonBox::rejected, &dlg, &QDialog::reject);

            if (dlg.exec() == QDialog::Accepted)
            {
                // 更新存储的值
                m_leftRegisterValue = sbLeft.value();
                m_rightRegisterValue = sbRight.value();
                // 发射写寄存器信号
                emit writeRegisterRequested(m_propValue, sbLeft.value());
                emit writeRegisterRequested(m_propValue2, sbRight.value());
                // 打印日志
                QString log = QString("设置寄存器 D%1 = %2, D%3 = %4")
                                  .arg(m_propValue).arg(m_leftRegisterValue)
                                  .arg(m_propValue2).arg(m_rightRegisterValue);
                emit logMessageRequested(log);
                // 更新显示
                update();
            }
        }
        else if (chosen == copyAct)
        {
            if (auto* scene = qobject_cast<PlcGraphicsScene*>(this->scene()))
            {
                scene->copyFrom(this);
            }
        }
        else if (chosen == delAct)
        {
            if (auto* scene = qobject_cast<PlcGraphicsScene*>(this->scene()))
            {
                scene->deleteSelectedItems();
            }
        }
    }
    event->accept();
}

QPointF PlcElement::leftConnectionPoint() const
{
    return QPointF(0, m_height / 2);
}

QPointF PlcElement::rightConnectionPoint() const
{
    return QPointF(m_width, m_height / 2);
}

// 添加连接点命中检测
bool PlcElement::isConnectionPointHit(const QPointF& pos, bool& isLeft) const
{
    // （被打断的旧内容删除）
    const int midY = static_cast<int>(m_height / 2.0);
    const int circleRadius = 3;               // 绘制时使用的半径
    const qreal hitRadius  = circleRadius+4;  // 命中半径更宽松，提升易用性

    // 注意：绘制时圆心为 (circleRadius, midY) 与 (m_width - circleRadius, midY)
    const QPointF leftCenter (circleRadius, midY);
    const QPointF rightCenter(m_width - circleRadius, midY);

    if (QLineF(pos, leftCenter).length() <= hitRadius)
    {
        isLeft = true;
        return true;
    }
    if (QLineF(pos, rightCenter).length() <= hitRadius)
    {
        isLeft = false;
        return true;
    }
    return false;
}

void PlcElement::paint(QPainter *painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
    Q_UNUSED(option);
    Q_UNUSED(widget);

    if (m_type == PlcInstructionType::NormallyClosed)
    {
        if (!m_on)
        {  // 常闭触点OFF状态（通路）时显示背景
            painter->save();
            painter->setPen(Qt::NoPen);
            painter->setBrush(QColor(200, 255, 200));
            painter->drawRect(boundingRect());
            painter->restore();
        }
    }
    else if (m_on)
    {  // 其他元件ON状态时显示背景
        painter->save();
        painter->setPen(Qt::NoPen);
        painter->setBrush(QColor(200, 255, 200));
        painter->drawRect(boundingRect());
        painter->restore();
    }

    painter->setRenderHint(QPainter::Antialiasing);
    QPen pen(Qt::black, 2);
    painter->setPen(pen);

    // 计算左右端点位置
    int midY = m_height / 2;
    int leftMargin = 20;
    int rightMargin = m_width - 20;
    const int circleRadius = 3; // 圆半径（直径6px）
    QPointF leftCircleCenter(circleRadius, midY); // 左圆圆心：左边缘与(0, midY)对齐
    QPointF rightCircleCenter(m_width - circleRadius, midY); // 右圆圆心：右边缘与(m_width, midY)对齐
    // 绘制左右水平电源线
    painter->drawLine(0, midY, leftMargin, midY);          // 左侧线
    painter->drawLine(rightMargin, midY, m_width, midY);   // 右侧线

    // 添加左右端点实心圆
    painter->setBrush(Qt::black);  // 设置填充颜色为黑色
    // 左端点圆形：左边缘与左侧电源线起点(0, midY)对齐
    painter->drawEllipse(leftCircleCenter, circleRadius, circleRadius);
    // 右端点圆形：右边缘与右侧电源线终点(m_width, midY)对齐
    painter->drawEllipse(rightCircleCenter, circleRadius, circleRadius);
    painter->setBrush(Qt::NoBrush);  // 恢复默认无填充

    switch (m_type)
    {
    case PlcInstructionType::NormallyOpen:
    {
        // 常开触点
        verticalLine(painter, leftMargin, rightMargin);
        break;
    }
    case PlcInstructionType::NormallyClosed:
    {
        // 常闭触点
        verticalLine(painter, leftMargin, rightMargin);
        painter->drawLine(leftMargin, m_height - 5, rightMargin, 5); // 斜杠
        break;
    }
    case PlcInstructionType::Coil:
    {
        // 线圈
        // 总宽度和高度
        int width = rightMargin - leftMargin;
        int height = m_height - 10;
        // 左侧括号和右侧括号
        painter->drawArc(leftMargin, 5, width/2, height, 90*16, 180*16);
        painter->drawArc(leftMargin + width/2, 5, width/2, height, 270*16, 180*16);
        break;
    }
    case PlcInstructionType::Greater:
    {
        // 大于：默认竖线 + 放大">"符号
        verticalLine(painter, leftMargin, rightMargin);
        enlarge(painter, leftMargin, rightMargin, ">");
        break;
    }
    case PlcInstructionType::GreaterEqual:
    {
        // 大于等于：默认竖线 + 放大"≥"符号
        verticalLine(painter, leftMargin, rightMargin);
        enlarge(painter, leftMargin, rightMargin, "≥");
        break;
    }
    case PlcInstructionType::Less:
    {
        // 小于：默认竖线 + 放大"<"符号
        verticalLine(painter, leftMargin, rightMargin);
        enlarge(painter, leftMargin, rightMargin, "<");
        break;
    }
    case PlcInstructionType::LessEqual:
    {
        // 小于等于：默认竖线 + 放大"≤"符号
        verticalLine(painter, leftMargin, rightMargin);
        enlarge(painter, leftMargin, rightMargin, "≤");
        break;
    }
    case PlcInstructionType::Equal:
    {
        // 等于：默认竖线 + 放大"="符号
        verticalLine(painter, leftMargin, rightMargin);
        enlarge(painter, leftMargin, rightMargin, "=");
        break;
    }
    case PlcInstructionType::NotEqual:
    {
        // 不等于：默认竖线 + 放大"≠"符号
        verticalLine(painter, leftMargin, rightMargin);
        enlarge(painter, leftMargin, rightMargin, "≠");
        break;
    }
    }

    // 在元件上方显示属性文本
    // 更小的上方标签区域，让文字更靠近元件
    static const qreal kLabelSpace      = 12.0;
    static const qreal kLabelOffsetDown = 2.0;    // 往下（靠近元件）偏移一点
    static const qreal kSidePadding     = 2.0;    // 左右留一点内边距避免贴边

    // 统一字体大小：显式使用小的像素字体
    painter->save();
    QFont f = painter->font();
    f.setPixelSize(10);                // 比默认明显更小
    painter->setFont(f);
    painter->setPen(Qt::black);

    // 标签区域：紧贴元件上方
    const QRectF topRect(0,
                         -kLabelSpace + kLabelOffsetDown,
                         m_width,
                         kLabelSpace);

    if (m_type == PlcInstructionType::NormallyOpen ||
        m_type == PlcInstructionType::NormallyClosed ||
        m_type == PlcInstructionType::Coil)
    {
        // 正上方居中：M + 值
        const QString text = QStringLiteral("M%1").arg(m_propValue);
        painter->drawText(topRect, Qt::AlignHCenter | Qt::AlignVCenter, text);
    }
    else
    {
        // 其余比较类：一行左右各一个 D<number>
        QRectF leftRect (topRect.left()  + kSidePadding,
                        topRect.top(),
                        topRect.width() / 2.0 - kSidePadding,
                        topRect.height());

        QRectF rightRect(topRect.left() + topRect.width() / 2.0,
                         topRect.top(),
                         topRect.width() / 2.0 - kSidePadding,
                         topRect.height());

        const QString d1 = QStringLiteral("D%1").arg(m_propValue);   // 左
        const QString d2 = QStringLiteral("D%1").arg(m_propValue2);  // 右

        painter->drawText(leftRect,  Qt::AlignHCenter | Qt::AlignVCenter, d1);
        painter->drawText(rightRect, Qt::AlignHCenter | Qt::AlignVCenter, d2);
    }

    if (isComparator())
    {
        static const qreal kLabelSpace      = 12.0;   // 与上方一致
        static const qreal kLabelOffsetDown = 2.0;    // 上方用的是“往下偏移”，这里复用
        static const qreal kSidePadding     = 2.0;

        painter->save();
        QFont f2 = painter->font();
        f2.setPixelSize(10);               // 与上方标签一致
        painter->setFont(f2);
        painter->setPen(Qt::black);

        // 让下方区域“紧贴元件下边缘”，并稍稍往上顶一点，避免与元件脱节。
        // 取一个与上方对称、略微“贴身”的矩形。
        const qreal y = m_height - kLabelOffsetDown;   // 顶部略压住元件下边沿，使之更“贴身”
        const QRectF bottomRect(0, y, m_width, kLabelSpace);

        // 左半区：显示左寄存器实际值
        const QRectF leftRect(kSidePadding,
                              bottomRect.y(),
                              bottomRect.width() * 0.5 - 2*kSidePadding,
                              bottomRect.height());

        // 右半区：显示右寄存器实际值
        const QRectF rightRect(bottomRect.x() + bottomRect.width() * 0.5 + kSidePadding,
                               bottomRect.y(),
                               bottomRect.width() * 0.5 - 2*kSidePadding,
                               bottomRect.height());

        painter->drawText(leftRect,
                          Qt::AlignHCenter | Qt::AlignVCenter,
                          QString::number(m_leftRegisterValue));
        painter->drawText(rightRect,
                          Qt::AlignHCenter | Qt::AlignVCenter,
                          QString::number(m_rightRegisterValue));
        painter->restore();
    }

    painter->restore();

    // 如果选中，加框
    if (isSelected())
    {
        painter->setPen(QPen(Qt::gray, 1, Qt::DashLine));
        painter->drawRect(boundingRect());
    }
}

void PlcElement::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    if (event->button() == Qt::LeftButton)
    {
        bool isLeft = false;
        if (isConnectionPointHit(event->pos(), isLeft))
        {
            // 点击了连接点，开始连线
            m_dragState = Connecting;
            m_dragFromRight = !isLeft; // 右侧连接点是起点

            // 通知场景开始连线
            PlcGraphicsScene* plcScene = qobject_cast<PlcGraphicsScene*>(scene());
            if (plcScene)
            {
                plcScene->startConnectionDrag(this, m_dragFromRight);
            }
            event->accept();
            return;
        } else
        {
            // 其他位置，开始移动元件
            m_dragState = Moving;
            m_dragStartPos = event->scenePos();
        }
    }

    QGraphicsObject::mousePressEvent(event);
}

void PlcElement::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    if (m_dragState == Connecting)
    {
        // 处理连线拖动
        PlcGraphicsScene* plcScene = qobject_cast<PlcGraphicsScene*>(scene());
        if (plcScene)
        {
            plcScene->updateConnectionDrag(mapToScene(event->pos()));
        }
        event->accept();
        return;
    }

    // 只处理左键拖动
    if (!(event->buttons() & Qt::LeftButton))
    {
        return;
    }

    if (!(flags() & QGraphicsItem::ItemIsMovable))
    {
        QGraphicsObject::mouseMoveEvent(event);
        return;
    }

    // 计算移动后的位置
    QPointF delta = event->scenePos() - m_dragStartPos;
    QPointF newPos = pos() + delta;

    // 获取视图
    QList<QGraphicsView*> views = scene()->views();
    if (views.isEmpty())
    {
        QGraphicsObject::mouseMoveEvent(event);
        return;
    }
    QGraphicsView* view = views.first();

    // 获取视口矩形（像素坐标）
    QRect viewportRect = view->viewport()->rect();

    // 将视口矩形映射到场景坐标
    QPointF topLeftScene = view->mapToScene(viewportRect.topLeft());
    QPointF bottomRightScene = view->mapToScene(viewportRect.bottomRight());
    QRectF visibleSceneRect(topLeftScene, bottomRightScene);

    // 组件的边界矩形（局部坐标）
    QRectF bounds = boundingRect();

    // 计算移动后组件边界矩形（在场景坐标）
    QRectF newBounds = bounds.translated(newPos);

    // 限制组件边界必须完全在视图可见区域内
    double limitedX = newPos.x();
    double limitedY = newPos.y();

    if (newBounds.left() < visibleSceneRect.left())
    {
        limitedX += visibleSceneRect.left() - newBounds.left();
    }
    if (newBounds.top() < visibleSceneRect.top())
    {
        limitedY += visibleSceneRect.top() - newBounds.top();
    }
    if (newBounds.right() > visibleSceneRect.right())
    {
        limitedX -= newBounds.right() - visibleSceneRect.right();
    }
    if (newBounds.bottom() > visibleSceneRect.bottom())
    {
        limitedY -= newBounds.bottom() - visibleSceneRect.bottom();
    }
    setPos(QPointF(limitedX, limitedY));
    m_dragStartPos = event->scenePos(); // 更新起始位置为当前位置
    event->accept();

    // 移动后更新所有连接的连线位置
    foreach (ConnectionItem *conn, m_connections)
    {
        conn->updatePosition();
    }
}

void PlcElement::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    // 1) 若当前是连线拖拽，仍按原逻辑交给场景处理并返回
    if (m_dragState == Connecting)
    {
        m_dragState = None;
        if (auto* plcScene = qobject_cast<PlcGraphicsScene*>(scene()))
        {
            // 传递鼠标释放时的场景坐标（供场景检测目标连接点）
            plcScene->endConnectionDrag(event->scenePos());
        }
        event->accept();
        return;
    }

    // 2) 左键松手：先做网格吸附
    if (event->button() == Qt::LeftButton)
    {
        if (auto *plcScene = qobject_cast<PlcGraphicsScene*>(scene()))
        {
            const QSizeF itemSize(boundingRect().width(), boundingRect().height());
            const QPointF wantedTopLeft = plcScene->snapTopLeftToCellCenter(scenePos(), itemSize);
            setPos(wantedTopLeft);

            // 3) 如果本次是“移动”结束，尝试将该元件插入到命中的水平连线上
            if (m_dragState == Moving)
            {
                plcScene->insertConnection(this);
            }
        }
        m_dragState = None;
    }

    // 4) 交给基类处理剩余事件
    QGraphicsObject::mouseReleaseEvent(event);

    // 5) 位置变化后，更新现有所有连接的连线位置
    for (auto *conn : m_connections)
    {
        if (conn) conn->updatePosition();
    }
}
